﻿/*
 *  Author: Louis A. Leskoviansky
 *  Company: Artemis Solutions Group (http://www.artemis-solutions.com)
 */


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace AjaxControlFramework
{
    [ParseChildren(ChildrenAsProperties = true, DefaultProperty = "SourceCode")]
    public class Script : BaseScriptControl
    {
        //------// Properties \\--------------------------------------------\\
        private string _src = String.Empty; // default value
        public virtual string Src
        {
            get { return _src; }
            set
            {
                if (value == null)
                {
                    _src = String.Empty;
                }
                else
                {
                    _src = value;
                }
            }
        }


        private string _assembly = String.Empty; // default value
        public virtual string Assembly
        {
            get { return _assembly; }
            set
            {
                if (value == null)
                {
                    _assembly = String.Empty;
                }
                else
                {
                    _assembly = value;
                }
            }
        }


        private string _qualifiedName = String.Empty; // default value
        public virtual string QualifiedName
        {
            get { return _qualifiedName; }
            set
            {
                if (value == null)
                {
                    _qualifiedName = String.Empty;
                }
                else
                {
                    _qualifiedName = value;
                }
            }
        }


        private string _sourceCode = String.Empty;

        [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
        public virtual string SourceCode
        {
            get { return _sourceCode; }
            set { _sourceCode = value; }
        }
        //------\\ Properties //--------------------------------------------//



        //------// Constructors \\------------------------------------------\\
        public Script()
            : base()
        { }
        //------\\ Constructors //------------------------------------------//



        //------// Methods \\-----------------------------------------------\\
        public override void ValidateProperties()
        {
            // Ensure that the properties that are provided values follow the following rules:
            
            // 1.) If the Type property is not explicitly provided in the markup, determine the value of 
            //     the property based on what other properties are explicitly provided.
            if (!_type.HasValue)
            {
                if (!String.IsNullOrEmpty(Src) && !String.IsNullOrEmpty(QualifiedName))
                {
                    throw new InvalidOperationException("The Src and QualifiedName properties cannot both be provided for Script controls. Only one of the two properties may be present.");
                }
                else if (String.IsNullOrEmpty(Src) && String.IsNullOrEmpty(QualifiedName) && (SourceCode == null || SourceCode.Trim() == String.Empty))
                {
                    throw new InvalidOperationException("The Src or QualifiedName property must be provided for all Script controls.");
                }
                else if (!String.IsNullOrEmpty(Src))
                {
                    if (SourceCode != null && SourceCode.Trim() != String.Empty)
                    {
                        throw new InvalidOperationException("SourceCode is not valid when the Src property is present.");
                    }

                    Type = ScriptType.File;

                    if (String.IsNullOrEmpty(Name))
                    {
                        Name = Src;
                    }
                }
                else if (!String.IsNullOrEmpty(QualifiedName))
                {
                    if (SourceCode != null && SourceCode.Trim() != String.Empty)
                    {
                        throw new InvalidOperationException("SourceCode is not valid when the QualifiedName property is present.");
                    }

                    Type = ScriptType.Embedded;

                    if (String.IsNullOrEmpty(Name))
                    {
                        Name = QualifiedName;
                    }
                }
                else if (SourceCode != null && SourceCode.Trim() != String.Empty)
                {
                    Type = ScriptType.Inline;

                    if (String.IsNullOrEmpty(Name))
                    {
                        throw new InvalidOperationException("The Name property is required for all Script controls of Type 'Inline'.");
                    }
                }
            }
            else
            {
                switch (_type.Value)
                {
                    case ScriptType.Embedded:

                        // The QualifiedName property is required. The Assembly property is optional 
                        // (not having this property defaults the internals to make reference to the 
                        // ExecutingAssembly.

                        if (String.IsNullOrEmpty(QualifiedName))
                        {
                            throw new InvalidOperationException("The QualifiedName property is required for all Script controls of Type 'Embedded'.");
                        }
                        else if (!String.IsNullOrEmpty(Src))
                        {
                            throw new InvalidOperationException("The Src property of the Script control is not valid when the Type is 'Embedded'.");
                        }

                        break;

                    case ScriptType.File:

                        // The Src property is required.

                        if (String.IsNullOrEmpty(Src))
                        {
                            throw new InvalidOperationException("The Src property is required for all Script controls of Type 'File'.");
                        }
                        else if (!String.IsNullOrEmpty(QualifiedName))
                        {
                            throw new InvalidOperationException("The QualifiedName property of the Script control is not valid when the Type is 'File'.");
                        }

                        break;

                    case ScriptType.Inline:

                        if (!String.IsNullOrEmpty(Src))
                        {
                            throw new InvalidOperationException("The Src property of the Script control is not valid when the Type is 'Inline'.");
                        }
                        else if (!String.IsNullOrEmpty(QualifiedName))
                        {
                            throw new InvalidOperationException("The QualifiedName property of the Script control is not valid when the Type is 'Inline'.");
                        }
                        
                        break;
                }
            }
        }


        public override void RenderControl(HtmlTextWriter writer)
        {
            DataBind();

            if (InternalScriptManager.Instance.RegisteredScripts.ContainsKey(Name))
            {
                ScriptReference scriptReference = InternalScriptManager.Instance.RegisteredScripts[Name];

                if (!scriptReference.IsRendered)
                {
                    writer.Write(scriptReference.GenerateScriptBlock());

                    InternalScriptManager.Instance.RenderedScripts.Add(Name, scriptReference);
                }
            }
        }


        public override ScriptReference GenerateScriptReference()
        {
            ScriptReference scriptReference = null;

            switch (Type)
            {
                case ScriptType.Embedded:

                    scriptReference = new EmbeddedScriptReference(Name, QualifiedName, Assembly);
                    break;

                case ScriptType.File:

                    scriptReference = new FileScriptReference(Name, Src);
                    break;

                case ScriptType.Inline:

                    scriptReference = new InlineScriptReference(Name, SourceCode);
                    break;
            }

            if (scriptReference == null) { return null; }

            scriptReference.Dependencies = new List<string>(Dependencies);

            return scriptReference;
        }
        //------\\ Methods //-----------------------------------------------//
    }
}
